﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using tms.Admins.Dto;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using System.Net;
using System.Security.Claims;
using System.Net.Http;
using tms.Utility;
using IdentityModel;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Extensions.Configuration;
using System.IdentityModel.Tokens.Jwt;
using Volo.Abp.Account;
using RegisterDto = tms.Admins.Dto.RegisterDto;
using tms.Filters;
using Namotion.Reflection;
using tms.Menus.Dto;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.ObjectMapping;

namespace tms.Admins
{
    /// <summary>
    /// 管理员
    /// </summary>
    [CustomerAuth]
    [ApiExplorerSettings(GroupName = "v1")]
    public class AdminService : CrudAppService<Admin, AdminDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateAdminDto>, IAdminService
    {
        private readonly IRepository<Admin, Guid> repository;
        private readonly IRepository<Admin_Role, Guid> repoAdminRoles;
        private readonly IRepository<Menu, Guid> repoMenu;
        private readonly IRepository<Menu_Role, Guid> repoMenuRoles;
        private readonly IHttpContextAccessor httpContext;
        private readonly IConfiguration configuration;
        private readonly ILogger<AdminService> logger;

        public AdminService(
            IRepository<Admin, Guid> repository, 
            IRepository<Admin_Role, Guid> repoAdminRoles,
            IRepository<Menu, Guid> repoMenu,
            IRepository<Menu_Role, Guid> repoMenuRoles,
            IHttpContextAccessor httpContext,
            IConfiguration configuration,
            ILogger<AdminService> logger
            ) : base(repository)
        {
            this.repository = repository;
            this.repoAdminRoles = repoAdminRoles;
            this.repoMenu = repoMenu;
            this.repoMenuRoles = repoMenuRoles;
            this.httpContext = httpContext;
            this.configuration = configuration;
            this.logger = logger;
        }

        public override Task<AdminDto> CreateAsync(CreateUpdateAdminDto input)
        {
            return base.CreateAsync(input);
        }

        #region 注册
        /// <summary>
        /// 注册
        /// </summary>
        /// <param name="adminDto"></param>
        /// <returns></returns>
        [HttpPost("/Admin/Register")]
        public async Task<ResultDto<AdminDto>> Register(RegisterDto adminDto)
        {
            var Admin = await repository.AnyAsync(m => m.UserName == adminDto.UserName);
            if (Admin)
            {
                return new ResultDto<AdminDto> { Code = ResultState.Failed,  Msg = "用户已存在" };
            }
            adminDto.Password = MD5Helper.GetPassword(adminDto.Password);
            var entity = ObjectMapper.Map<RegisterDto, Admin>(adminDto);
            var admin = await repository.InsertAsync(entity);
            var dto = ObjectMapper.Map<Admin, AdminDto>(admin);
            return new ResultDto<AdminDto> { Code =  ResultState.Success, Msg = "注册成功", Data = dto };
        }
        #endregion

        #region 用户登录
        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="loginDto"></param>
        /// <returns></returns>
        [HttpPost("/admin/login")]
        [AllowAnonymous]
        public async Task<LoginResultDto> Login(LoginDto loginDto)
        {
            var Admin = await repository.FirstOrDefaultAsync(m => m.UserName == loginDto.UserName);

            if (Admin == null)
            {
                return new LoginResultDto { LoginState = LoginState.NoUser, Msg = LoginState.NoUser.EnumToDescription() };
            }
            else
            {
                if (Admin.Password != MD5Helper.GetPassword(loginDto.Password))
                {
                    return new LoginResultDto { LoginState = LoginState.PasswordError, Msg = LoginState.PasswordError.GetSummary() };
                }
                else
                {
                    //更新末次登录时间
                    Admin.LastLoginTime = DateTime.Now;
                    Admin.LastLoginIP = httpContext.HttpContext.GetRemoteIPAddress().ToString();
                    await repository.UpdateAsync(Admin);

                    //查询角色信息
                    var roleIds = repoAdminRoles.Where(m => m.AdminId == Admin.Id).Select(m => m.RoleId).ToList();

                    IList<Claim> claims = new List<Claim> {
                        new Claim(JwtClaimTypes.Id,Admin.Id.ToString()),
                        new Claim(ClaimTypes.Name, loginDto.UserName),
                        new Claim(ClaimTypes.Role, string.Join(',',roleIds))
                    };

                    //JWT密钥
                    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JwtConfig:Bearer:SecurityKey"]));

                    //算法
                    var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

                    //过期时间
                    DateTime expires = DateTime.UtcNow.AddHours(10);


                    //Payload负载
                    var token = new JwtSecurityToken(
                        issuer: configuration["JwtConfig:Bearer:Issuer"],
                        audience: configuration["JwtConfig:Bearer:Audience"],
                        claims: claims,
                        notBefore: DateTime.UtcNow,
                        expires: expires,
                        signingCredentials: cred
                        );

                    var handler = new JwtSecurityTokenHandler();

                    //生成令牌
                    string jwt = handler.WriteToken(token);

                    return new LoginResultDto { LoginState = LoginState.Success, Token = jwt, Msg = LoginState.Success.GetSummary() };
                }
            }
        }
        #endregion

        #region 更新用户角色
        /// <summary>
        /// 更新用户角色
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("/admin/UpdateAdminRole")]
        public async Task UpdateAdminRole(UpdateAdminRoleDto dto)
        {
            await repoAdminRoles.InsertManyAsync(dto.RoleId.Select(m => new Admin_Role {
                AdminId = dto.Id,
                RoleId = m
            }));
        }
        #endregion

        #region 根据角色获取菜单
        /// <summary>
        /// 根据角色获取菜单
        /// </summary>
        /// <returns></returns>
        [HttpGet("/Admin/GetMenu")]
        [Authorize]
        public async Task<ResultDto<List<MenuDto>>> GetMenu()
        {
            try
            {
                var RoleId = httpContext.HttpContext.User.Claims.FirstOrDefault(m => m.Type == ClaimTypes.Role).Value
                    .Split(',').Select(m => Guid.Parse(m));

                var list = (await repoMenu.GetQueryableAsync()).Where(menu =>
                    repoMenuRoles.Where(menurole => RoleId.Contains(menurole.RoleId))
                    .Select(m => m.MenuId).
                    Contains(menu.Id)
                ).ToList();

                return new ResultDto<List<MenuDto>> { Code = ResultState.Success, Data = ObjectMapper.Map<List<Menu>, List<MenuDto>>(list) };
            }
            catch (Exception e)
            {
                logger.LogError("获取角色异常", e);
                return new ResultDto<List<MenuDto>> { Code = ResultState.Failed, Msg = $"获取角色异常 {e.Message}{e.Source}"};
            }
        }
    }
    #endregion
}